
// === uuColor ===
// depend: uuMeta
/*
uuColor.hash
uuColor.hex(rgba) - return HexColorString("#ffffff")
uuColor.rgba(rgba) - return RGBAColorString("rgba(0,0,0,0)")
uuColor.arrange(rgba, h = 0, s = 0, v = 0) - return RGBAHash
uuColor.comple(rgba) - return RGBAHash
uuColor.gray(rgba) - return RGBAHash
uuColor.sepia(rgba) - return RGBAHash
uuColor.parse(color, toRGBA = 0, valid) - return ["#ffffff", alpha] or RGBAHash
uuColor.hex2rgba(hex) - return RGBAHash
uuColor.rgba2hsva(rgba) - return HSVAHash
uuColor.hsva2rgba(hsva) - return RGBAHash
uuColor.rgba2hsla(rgba) - return HSLAHash
uuColor.hsla2rgba(hsla) - return RGBAHash
 */
(function() {
var _color, // inner namespace
    _mm = uuMeta,
    _float = parseFloat,
    _math = Math,
    _round = _math.round,
    _hex = _mm.hex,
    PARSE_HEX = /^#(([\da-f])([\da-f])([\da-f]))(([\da-f])([\da-f]{2}))?$/,
    PARSE_PERCENT = /[\d\.]+%/g,
    PARSE_RGBA =
      /(rgba?)\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d\.]+))?\s*\)/;

_color = {
  // uuColor.hash - color hash
  hash: (function() { // Hash( { black: "#000000" } )
    var rv = [], v, i = 0, iz, item = (
// FAMICOM(R) Named Color(from "FC00" to "FC3F")
"7b7b7bfc00,0000fffc01,0000bdfc02,4229bdfc03,940084fc04,ad0021fc05,8c1000fc06,"+
"8c1000fc07,522900fc08,007300fc09,006b00fc0a,005a00fc0b,004252fc0c,000000fc0d,"+
"000000fc0e,000000fc0f,bdbdbdfc10,0073f7fc11,0052f7fc12,6b42fffc13,de00cefc14,"+
"e7005afc15,f73100fc16,e75a10fc17,ad7b00fc18,00ad00fc19,00ad00fc1a,00ad42fc1b,"+
"008c8cfc1c,000000fc1d,000000fc1e,000000fc1f,f7f7f7fc20,39bdfffc20,6b84fffc22,"+
"9473f7fc23,f773f7fc24,f75294fc25,f77352fc26,ffa542fc27,f7b500fc28,b5f710fc29,"+
"5ade52fc2a,52f794fc2b,00efdefc2c,737373fc2d,000000fc2e,000000fc2f,fffffffc30,"+
"a5e7fffc31,b5b5f7fc32,d6b5f7fc33,f7b5f7fc34,ffa5c6fc35,efceadfc36,ffe7adfc37,"+
"ffde7bfc38,d6f773fc39,b5f7b5fc3a,b5f7d6fc3b,00fffffc3c,f7d6f7fc3d,000000fc3e,"+
"000000fc3f,"+
// W3C Named Color
"000000black,888888gray,ccccccsilver,ffffffwhite,ff0000red,"+
"ffff00yellow,00ff00lime,00ffffaqua,00ffffcyan,0000ffblue,ff00fffuchsia,"+
"ff00ffmagenta,880000maroon,888800olive,008800green,008888teal,000088navy,"+
"880088purple,696969dimgray,808080gray,a9a9a9darkgray,c0c0c0silver,"+
"d3d3d3lightgrey,dcdcdcgainsboro,f5f5f5whitesmoke,fffafasnow,708090slategray,"+
"778899lightslategray,b0c4delightsteelblue,4682b4steelblue,5f9ea0cadetblue,"+
"4b0082indigo,483d8bdarkslateblue,6a5acdslateblue,7b68eemediumslateblue,"+
"9370dbmediumpurple,f8f8ffghostwhite,00008bdarkblue,0000cdmediumblue,"+
"4169e1royalblue,1e90ffdodgerblue,6495edcornflowerblue,87cefalightskyblue,"+
"add8e6lightblue,f0f8ffaliceblue,191970midnightblue,00bfffdeepskyblue,"+
"87ceebskyblue,b0e0e6powderblue,2f4f4fdarkslategray,00ced1darkturquoise,"+
"afeeeepaleturquoise,f0ffffazure,008b8bdarkcyan,20b2aalightseagreen,"+
"48d1ccmediumturquoise,40e0d0turquoise,7fffd4aquamarine,e0fffflightcyan,"+
"00fa9amediumspringgreen,7cfc00lawngreen,00ff7fspringgreen,7fff00chartreuse,"+
"adff2fgreenyellow,2e8b57seagreen,3cb371mediumseagreen,66cdaamediumaquamarine,"+
"98fb98palegreen,f5fffamintcream,006400darkgreen,228b22forestgreen,"+
"32cd32limegreen,90ee90lightgreen,f0fff0honeydew,556b2fdarkolivegreen,"+
"6b8e23olivedrab,9acd32yellowgreen,8fbc8fdarkseagreen,9400d3darkviolet,"+
"8a2be2blueviolet,dda0ddplum,d8bfd8thistle,8b008bdarkmagenta,9932ccdarkorchid,"+
"ba55d3mediumorchid,da70d6orchid,ee82eeviolet,e6e6falavender,"+
"c71585mediumvioletred,bc8f8frosybrown,ff69b4hotpink,ffc0cbpink,"+
"ffe4e1mistyrose,ff1493deeppink,db7093palevioletred,e9967adarksalmon,"+
"ffb6c1lightpink,fff0f5lavenderblush,cd5c5cindianred,f08080lightcoral,"+
"f4a460sandybrown,fff5eeseashell,dc143ccrimson,ff6347tomato,ff7f50coral,"+
"fa8072salmon,ffa07alightsalmon,ffdab9peachpuff,ffffe0lightyellow,"+
"b22222firebrick,ff4500orangered,ff8c00darkorange,ffa500orange,"+
"ffd700gold,fafad2lightgoldenrodyellow,8b0000darkred,a52a2abrown,"+
"a0522dsienna,b8860bdarkgoldenrod,daa520goldenrod,deb887burlywood,f0e68ckhaki,"+
"fffacdlemonchiffon,d2691echocolate,cd853fperu,bdb76bdarkkhaki,bdb76btan,"+
"eee8aapalegoldenrod,f5f5dcbeige,ffdeadnavajowhite,ffe4b5moccasin,"+
"ffe4c4bisque,ffebcdblanchedalmond,ffefd5papayawhip,fff8dccornsilk,"+
"f5deb3wheat,faebd7antiquewhite,faf0e6linen,fdf5e6oldlace,fffaf0floralwhite,"+
"fffff0ivory").split(",");

    for (iz = item.length; i < iz; ++i) {
      v = item[i];
      rv[v.slice(6)] = "#" + v.slice(0, 6);
    }
    return rv;
  })(),

  // uuColor.hex - return Hex Color String( "#ffffff" )
  hex: function(rgba) { // @param RGBAHash: Hash( { r,g,b,a })
                        // @return HexColorString( "#ffffff" )
    return ["#", _hex[rgba.r], _hex[rgba.g], _hex[rgba.b]].join("");
  },

  // uuColor.rgba - return RGBA Color String( "rgba(0,0,0,0)" )
  rgba: function(rgba) { // @param RGBAHash: Hash( { r,g,b,a })
                         // @return RGBAColorString( "rgba(0,0,0,0)" )
    return "rgba(" + [rgba.r, rgba.g, rgba.b, rgba.a].join(",") + ")";
  },

  // uuColor.arrange - arrangemented color(Hue, Saturation and Value)
  //    Hue is absolure value,
  //    Saturation and Value is relative value.
  arrange: function(rgba, // @param RGBAHash: Hash( { r,g,b,a })
                    h,    // @param Number(=0): Hue (from -360 to 360)
                    s,    // @param Number(=0): Saturation (from -100 to 100)
                    v) {  // @param Number(=0): Value (from -100 to 100)
                          // @return RGBAHash:
    var rv = _color.rgba2hsva(rgba), r = 360;
    rv.h += h, rv.h = (rv.h > r) ? rv.h - r : (rv.h < 0) ? rv.h + r : rv.h;
    rv.s += s, rv.s = (rv.s > 100) ? 100 : (rv.s < 0) ? 0 : rv.s;
    rv.v += v, rv.v = (rv.v > 100) ? 100 : (rv.v < 0) ? 0 : rv.v;
    return _color.hsva2rgba(rv);
  },

  // uuColor.comple - complementary color
  comple: function(rgba) { // @param RGBAHash: Hash( { r,g,b,a })
                           // @return RGBAHash:
    return { r: rgba.r ^ 255, g: rgba.g ^ 255, b: rgba.b ^ 255, a: rgba.a };
  },

  // uuColor.gray - gray color (G channel method)
  gray: function(rgba) { // @param RGBAHash: Hash( { r,g,b,a })
                         // @return RGBAHash:
    return { r: rgba.g, g: rgba.g, b: rgba.g, a: rgba.a };
  },

  // uuColor.sepia - sepia color
  sepia: function(rgba) { // @param RGBAHash: Hash( { r,g,b,a })
                          // @return RGBAHash:
    var r = rgba.r, g = rgba.g, b = rgba.b,
        y = 0.2990 * r + 0.5870 * g + 0.1140 * b, u = -0.091, v = 0.056;

    r = y + 1.4026 * v;
    g = y - 0.3444 * u - 0.7114 * v;
    b = y + 1.7330 * u;
    r *= 1.2;
    b *= 0.8;
    return { r: r < 0 ? 0 : r > 255 ? 255 : r | 0,
             g: g < 0 ? 0 : g > 255 ? 255 : g | 0,
             b: b < 0 ? 0 : b > 255 ? 255 : b | 0, a: rgba.a };
  },

  // uuColor.parse - parse color
  //    RGBAColorString is "rgba(0,0,0,0)" style color string
  //    HexColorString is "#ffffff" style color string
  //    W3CNamedColorString is "pink" style color string
  parse: function(
      color,    // @parem RGBAColorString/HexColorString
                //        /W3CNamedColorString
      toRGBA,   // @param Boolean(= false): true = return RGBAHash
                //                          false = return Array
      valid) {  // @param Boolean(= false): true = validation mode
                //                                 (throw exception)
                //                          false = silent mode
                // @return Array/RGBAHash:
                //          [ HexColorString, Number(alpha) ]
                //          { r, g, b, a }
    var c = color.toLowerCase(), rv, m;

    if (c !== "transparent") {
      if (c in _color.hash) {
        rv = _color.hash[c];
        return toRGBA ? _color.hex2rgba(rv) : [rv, 1];
      }
      if ( (m = PARSE_HEX.exec(c)) ) {
        rv = (c.length > 4) ? c
                            : ["#", m[2], m[2],
                                    m[3], m[3],
                                    m[4], m[4]].join("");
        return toRGBA ? _color.hex2rgba(rv) : [rv, 1];
      }
      c = c.replace(PARSE_PERCENT, function(n) {
        return _math.min((_float(n) || 0) * 2.55, 255) | 0
      });
      if ( (m = PARSE_RGBA.exec(c)) ) {
        return toRGBA ? { r: m[2] | 0, g: m[3] | 0, b: m[4] | 0,
                          a: m[1] === "rgb" ? 1 : _float(m[5]) }
                      : [["#", _hex[m[2]], _hex[m[3]], _hex[m[4]]].join(""),
                         m[1] === "rgb" ? 1 : _float(m[5])];
      }
      if (valid) {
        throw color + " invalid color";
      }
    }
    return toRGBA ? { r: 0, g: 0, b: 0, a: 0 } : ["#000000", 0];
  },

  // uuColor.hex2rgba - convert "#ffffff" to RGBAHash
  hex2rgba: function(hex) { // @param HexColorString: String( "#ffffff" )
                            // @return RGBAHash: Hash( { r,g,b,a } )
    var n = parseInt(hex.slice(1), 16);
    return { r: (n >> 16) & 0xff, g: (n >> 8) & 0xff, b: n & 0xff, a: 1 };
  },

  // uuColor.rgba2hsva
  rgba2hsva: function(rgba) { // @param RGBAHash:
                              // @return HSVAHash:
    var r = rgba.r / 255, g = rgba.g / 255, b = rgba.b / 255,
        max = _math.max(r, g, b), diff = max - _math.min(r, g, b),
        h = 0, s = max ? _round(diff / max * 100) : 0, v = _round(max * 100);
    if (!s) {
      return { h: 0, s: 0, v: v, a: rgba.a };
    }
    h = (r === max) ? ((g - b) * 60 / diff) :
        (g === max) ? ((b - r) * 60 / diff + 120)
                    : ((r - g) * 60 / diff + 240);
    // HSVAHash( { h:360, s:100, v:100, a:1.0 } )
    return { h: (h < 0) ? h + 360 : h, s: s, v: v, a: rgba.a };
  },

  // uuColor.hsva2rgba
  hsva2rgba: function(hsva) { // @param HSVAHash:
                              // @return RGBAHash:
    var h = (hsva.h >= 360) ? 0 : hsva.h,
        s = hsva.s / 100,
        v = hsva.v / 100,
        a = hsva.a,
        h60 = h / 60, matrix = h60 | 0, f = h60 - matrix,
        v255, p, q, t, w;
    if (!s) {
      h = _round(v * 255);
      return { r: h, g: h, b: h, a: a };
    }
    v255 = v * 255,
    p = _round((1 - s) * v255),
    q = _round((1 - (s * f)) * v255),
    t = _round((1 - (s * (1 - f))) * v255),
    w = _round(v255);
    switch (matrix) {
      case 0: return { r: w, g: t, b: p, a: a };
      case 1: return { r: q, g: w, b: p, a: a };
      case 2: return { r: p, g: w, b: t, a: a };
      case 3: return { r: p, g: q, b: w, a: a };
      case 4: return { r: t, g: p, b: w, a: a };
      case 5: return { r: w, g: p, b: q, a: a };
    }
    return { r: 0, g: 0, b: 0, a: a };
  },

  // uuColor.rgba2hsla
  rgba2hsla: function(rgba) { // @param RGBAHash:
                              // @return HSLAHash:
    var r = rgba.r / 255,
        g = rgba.g / 255,
        b = rgba.b / 255,
        max = Math.max(r, g, b),
        min = Math.min(r, g, b),
        diff = max - min,
        h = 0, s = 0, l = (min + max) / 2;

    if (l > 0 && l < 1) {
      s = diff / (l < 0.5 ? l * 2 : 2 - (l * 2));
    }
    if (diff > 0) {
      if (max === r && max !== g) {
        h += (g - b) / diff;
      } else if (max === g && max !== b) {
        h += (b - r) / diff + 2;
      } else if (max === b && max !== r) {
        h += (r - g) / diff + 4;
      }
      h *= 60;
    }
    return { h: h, s: _round(s * 100), l: _round(l * 100), a: rgba.a };
  },

  // uuColor.hsla2rgba - ( h: 0-360, s: 0-100, l: 0-100, a: alpha )
  hsla2rgba: function(hsla) { // @param HSLAHash:
                              // @return RGBAHash:
    var h = (hsla.h === 360) ? 0 : hsla.h,
        s = hsla.s / 100,
        l = hsla.l / 100,
        r, g, b, s1, s2, l1, l2;

    if (h < 120) {
      r = (120 - h) / 60, g = h / 60, b = 0;
    } else if (h < 240) {
      r = 0, g = (240 - h) / 60, b = (h - 120) / 60;
    } else {
      r = (h - 240) / 60, g = 0, b = (360 - h) / 60;
    }
    s1 = 1 - s;
    s2 = s * 2;

    r = s2 * (r > 1 ? 1 : r) + s1;
    g = s2 * (g > 1 ? 1 : g) + s1;
    b = s2 * (b > 1 ? 1 : b) + s1;

    if (l < 0.5) {
      r *= l, g *= l, b *= l;
    } else {
      l1 = 1 - l;
      l2 = l * 2 - 1;
      r = l1 * r + l2;
      g = l1 * g + l2;
      b = l1 * b + l2;
    }
    return { r: _round(r * 255), g: _round(g * 255),
             b: _round(b * 255), a: hsla.a };
  }
};

// --- initialize ---

// --- export ---
window.uuColor = _color; // window.uuColor

})(); // uuColor scope
